package edu.cmu.ibill.controller;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

import javax.servlet.http.HttpServletRequest;

import org.mybeans.dao.DAOException;
import org.mybeans.factory.RollbackException;
import org.mybeans.factory.Transaction;

import edu.cmu.ibill.databeans.*;
import edu.cmu.ibill.model.*;

public class AddSharedBillAction extends Action {

	UserDAO userDAO;
	PersonalBillDAO personalDAO;
	DebtDAO debtDAO;
	CategoryDictDAO categorydictDAO;

	SimpleDateFormat format = new SimpleDateFormat("MM/dd/yyyy");

	String amount;
	String date;
	String comment;
	String category;

	public AddSharedBillAction(Model model) {
		this.debtDAO = model.getDebtDAO();
		this.personalDAO = model.getPersonalBillDAO();
		this.userDAO = model.getUserDAO();
		this.categorydictDAO = model.getCategoryDictDAO();
	}

	@Override
	public String getName() {
		return "addsharedbill.do";
	}

	@Override
	public String perform(HttpServletRequest request) {

		ArrayList<String> errors = new ArrayList<String>();
		request.setAttribute("addsharedbillerrors", errors);
		request.setAttribute("categorydict", categorydictDAO.getAllCategoryNames());
		User user = (User) request.getSession(false).getAttribute("user");

		if (user == null || user.getId() == -1) {
			request.getSession(false).setAttribute("user", null);

			// TODO return login?
			return "login.jsp";
		}

		// Get corresponding information from the request.
		amount = request.getParameter("amount");
		date = request.getParameter("date");
		comment = request.getParameter("comment");
		category = request.getParameter("category");
		
		request.setAttribute("addshared_amount", amount);
		request.setAttribute("addshared_date", date);
		request.setAttribute("addshared_comment", comment);
		request.setAttribute("addshared_category", category);

		String userprefix = "user";
		String amountprefix = "amount";

		ArrayList<String> sharedUserNameList = new ArrayList<String>();
		ArrayList<String> sharedUserList = new ArrayList<String>();
		ArrayList<Double> sharedAmountList = new ArrayList<Double>();

		int num = 1;

		/**
		 * Get all the users from request. I assume all the users have adjacent
		 * ids. e.g. user1, user2, user3. So if there is no more user, then the
		 * iteration will be terminated. I will also try to extract the
		 * associated shared amount for every shared user.
		 */

		while (true) {
			String tmpUserId = request.getParameter(userprefix + num);

			if (tmpUserId == null)
				break;
			else {
				sharedUserList.add(tmpUserId);
				sharedUserNameList.add(userDAO.getNamebyUserID(Integer.parseInt(tmpUserId)));
				String tmp = request.getParameter(amountprefix + num);
				double sharedamount = Double.parseDouble(tmp);
				sharedAmountList.add(sharedamount);
				
				request.setAttribute("addshared_"+userprefix + num, tmpUserId);
				request.setAttribute("addshared_"+amountprefix + num, tmp);
				tmp=request.getParameter("uname" + num);
				tmp=tmp.replace("\n", "").replace("\r", "").replace("\n\r", "").replace("\r\n", "");
				request.setAttribute("addshared_uname" + num, tmp);
				num++;
			}
		}

		// Validate the errors.
		errors.addAll(this.getValidationErrors());
		
		if (errors.size() != 0) {
			// TODO return something & add something to the request.

			PersonalBill[] pBills = personalDAO.LookupByUserId(user.getId());
			request.setAttribute("personalbills", pBills);
			request.setAttribute("addsharedbillinprocess", "");
			return "manage.jsp";
		}

		// Commit the personalBill and all the debt records to the database.
		try {
			// Use the information to intial the bill and store it into
			// database.
			PersonalBill pb = new PersonalBill();
			pb.setAmount(Double.parseDouble(amount));
			pb.setDate(new java.sql.Date(format.parse(date).getTime()));
			pb.setCategoryId(Integer.parseInt(category));
			pb.setDescription(comment);
			pb.setIsShared(true);
			pb.setUserId(user.getId());
			// Store the bill into database and get the bill id.
			int pbId = personalDAO.create(pb);
			
			// Create Debt records.
			for (int i = 0; i < sharedUserList.size(); i++) {
				String sUser = sharedUserList.get(i);
				// If the shared user is the payed user, then ignore it.
				if (Integer.parseInt(sUser) != user.getId()) {
					Debt debt = new Debt();
					// Set the amount.
					debt.setAmount(sharedAmountList.get(i));
					debt.setDate(pb.getDate());
					// Set the description.
					debt.setDescription(pb.getDescription());
					// Set the id of the personal bill which records the payment
					debt.setPayedBillId(pbId);
					// Set the id to -1, since no bill records who actually
					// receive the money.
					debt.setOwedBillId(-1);
					// Set the id of the user who paid the shared bill
					debt.setPayedId(pb.getUserId());
					// Set the id of the user who owes the shared bill
					debt.setOwedId(Integer.parseInt(sUser));

					debtDAO.create(debt);
				} else
					continue;
			}

			// TODO return something.
			PersonalBill[] pBills = personalDAO.LookupByUserId(user.getId());
			request.setAttribute("personalbills", pBills);
			
	        return "manage.jsp";
		} catch (ParseException e) {

			errors.add(e.getMessage());
			PersonalBill[] pBills = personalDAO.LookupByUserId(user.getId());
			request.setAttribute("personalbills", pBills);
			request.setAttribute("addsharedbillinprocess", "");
			return "manage.jsp";
		} catch (DAOException e) {
			// TODO Auto-generated catch block
			errors.add(e.getMessage());
			PersonalBill[] pBills = personalDAO.LookupByUserId(user.getId());
			request.setAttribute("personalbills", pBills);
			request.setAttribute("addsharedbillinprocess", "");
			return "manage.jsp";
		}finally {
			if (Transaction.isActive())
				Transaction.rollback();
		}
	}

	public List<String> getValidationErrors() {
		List<String> sb = new ArrayList<String>();

		if (date == null || date.length() == 0) {
			sb.add("date is empty");
		} else {
			SimpleDateFormat format = new SimpleDateFormat("MM/dd/yyyy");

			try {
				java.util.Date d = format.parse(date);
				Calendar currentDate = Calendar.getInstance();
				if (currentDate.getTime().before(d)) {
					sb.add("invalid date for a future time");
				}
			} catch (ParseException e) {
				sb.add("invalid format for date");
			}

		}

		if (category == null || category.length() == 0) {
			sb.add("category is empty");
		} else {
			if (Integer.parseInt(category) == 0) {
				sb.add("category is empty");
			}
		}

		if (amount == null || amount.length() == 0) {
			sb.add("amount is empty");
		} else {
			try {
				Double.parseDouble(amount);
			} catch (NumberFormatException e) {
				sb.add("invalid format for amount");
			}
		}
		return sb;
	}

}
